<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='global-property-'>/**
</span> * @ignore
 * draft for kissy editor
 * @author yiminghe@gmail.com
 */
KISSY.add(&quot;editor/plugin/draft&quot;, function (S, Json, Editor, localStorage, Overlay, MenuButton) {
    var Node = S.Node,
        LIMIT = 5,
        Event = S.Event,
        INTERVAL = 5,
        DRAFT_SAVE = &quot;ks-editor-draft-save20110503&quot;;

    function padding(n, l, p) {
        n += &quot;&quot;;
        while (n.length &lt; l) {
            n = p + n;
        }
        return n;
    }

    function date(d) {
        if (typeof d === 'number') {
            d = new Date(d);
        }
        if (d instanceof Date)
            return [
                d.getFullYear(),
                &quot;-&quot;,
                padding(d.getMonth() + 1, 2, &quot;0&quot;),
                &quot;-&quot;,
                padding(d.getDate(), 2, &quot;0&quot;),
                &quot; &quot;,
                //&quot;&amp;nbsp;&quot;,
                padding(d.getHours(), 2, &quot;0&quot;),
                &quot;:&quot;,
                padding(d.getMinutes(), 2, &quot;0&quot;),
                &quot;:&quot;,
                padding(d.getSeconds(), 2, &quot;0&quot;)
                //&quot;&amp;nbsp;&quot;,
                //&quot;&amp;nbsp;&quot;
            ].join(&quot;&quot;);
        else
            return d;
    }

    function Draft(editor, config) {
        this.editor = editor;
        this.config = config;
        this._init();
    }

    var addRes = Editor.Utils.addRes,
        destroyRes = Editor.Utils.destroyRes;

    S.augment(Draft, {
        _getSaveKey: function () {
            var self = this,
                cfg = self.config;
            return cfg.draft &amp;&amp; cfg.draft['saveKey'] || DRAFT_SAVE;
        },


        // parse 历史记录延后，点击 select 时才开始 parse
        _getDrafts: function () {
            var self = this;
            if (!self.drafts) {
                var str = localStorage.getItem(self._getSaveKey()),
                    drafts = [];
                if (str) {
                   // 原生 localStorage 必须串行化
                    drafts = (localStorage == window.localStorage) ?
                        Json.parse(S.urlDecode(str)) : str;
                }
                self.drafts = drafts;
            }
            return self.drafts;
        },

        _init: function () {
            var self = this,
                editor = self.editor,
                prefixCls = editor.get('prefixCls'),
                statusbar = editor.get(&quot;statusBarEl&quot;),
                cfg = this.config;
            cfg.draft = cfg.draft || {};
            self.draftInterval = cfg.draft.interval
                = cfg.draft.interval || INTERVAL;
            self.draftLimit = cfg.draft.limit
                = cfg.draft.limit || LIMIT;
            var holder = new Node(
                &quot;&lt;div class='&quot; + prefixCls + &quot;editor-draft'&gt;&quot; +
                    &quot;&lt;span class='&quot; + prefixCls + &quot;editor-draft-title'&gt;&quot; +
                    &quot;内容正文每&quot; +
                    cfg.draft.interval
                    + &quot;分钟自动保存一次。&quot; +
                    &quot;&lt;/span&gt;&quot; +
                    &quot;&lt;/div&gt;&quot;).appendTo(statusbar);
            self.timeTip = new Node(&quot;&lt;span class='&quot; + prefixCls + &quot;editor-draft-time'/&gt;&quot;)
                .appendTo(holder);

            var save = new Node(
                    S.substitute(&quot;&lt;a href='#' &quot; +
                        &quot;onclick='return false;' &quot; +
                        &quot;class='{prefixCls}editor-button &quot; +
                        &quot;{prefixCls}editor-draft-save-btn ks-inline-block' &quot; +
                        &quot;style='&quot; +
                        &quot;vertical-align:middle;&quot; +
                        &quot;padding:1px 9px;&quot; +
                        &quot;'&gt;&quot; +
                        &quot;&lt;span class='{prefixCls}editor-draft-save'&gt;&quot; +
                        &quot;&lt;/span&gt;&quot; +
                        &quot;&lt;span&gt;立即保存&lt;/span&gt;&quot; +
                        &quot;&lt;/a&gt;&quot;, {
                        prefixCls: prefixCls
                    })).unselectable(undefined).appendTo(holder),
                versions = new MenuButton({
                    render: holder,
                    collapseOnClick: true,
                    width: &quot;100px&quot;,
                    prefixCls: prefixCls + &quot;editor-&quot;,
                    menu: {
                        width: &quot;225px&quot;,
                        align: {
                            points: ['tr', 'br']
                        }
                    },
                    matchElWidth: false,
                    content: &quot;恢复编辑历史&quot;
                }).render();
            self.versions = versions;
            // 点击才开始 parse
            versions.on(&quot;beforeCollapsedChange&quot;, function (e) {
                if (!e.newValue) {
                    versions.detach(&quot;beforeCollapsedChange&quot;, arguments.callee);
                    self.sync();
                }
            });
            save.on(&quot;click&quot;, function (ev) {
                self.save(false);
                //如果不阻止，部分页面在ie6下会莫名奇妙把其他input的值丢掉！
                ev.halt();
            });

            addRes.call(self, save);

            /*
             监控form提交，每次提交前保存一次，防止出错
             */
            if (editor.get(&quot;textarea&quot;)[0].form) {
                (function () {
                    var textarea = editor.get(&quot;textarea&quot;),
                        form = textarea[0].form;

                    function saveF() {
                        self.save(true);
                    }

                    Event.on(form, &quot;submit&quot;, saveF);
                    addRes.call(self, function () {
                        Event.remove(form, &quot;submit&quot;, saveF);
                    });

                })();
            }

            var timer = setInterval(function () {
                self.save(true);
            }, self.draftInterval * 60 * 1000);

            addRes.call(self, function () {
                clearInterval(timer);
            });

            versions.on(&quot;click&quot;, self.recover, self);
            addRes.call(self, versions);
            self.holder = holder;
            if (cfg.draft['helpHTML']) {

                var help = new Node('&lt;a ' +
                    'tabindex=&quot;0&quot; ' +
                    'hidefocus=&quot;hidefocus&quot; ' +
                    'class=&quot;' + prefixCls + 'editor-draft-help&quot; ' +
                    'title=&quot;点击查看帮助&quot; ' +
                    'href=&quot;javascript:void(\'点击查看帮助 \')&quot;&gt;点击查看帮助&lt;/a&gt;')
                    .unselectable(undefined)
                    .appendTo(holder);

                help.on(&quot;click&quot;, function () {
                    help[0].focus();
                    if (self.helpPopup &amp;&amp; self.helpPopup.get(&quot;visible&quot;)) {
                        self.helpPopup.hide();
                    } else {
                        self._prepareHelp();
                    }
                });
                help.on(&quot;blur&quot;, function () {
                    self.helpPopup &amp;&amp; self.helpPopup.hide();
                });
                self.helpBtn = help;
                addRes.call(self, help);
                Editor.Utils.lazyRun(self, &quot;_prepareHelp&quot;, &quot;_realHelp&quot;);
            }
            addRes.call(self, holder);
        },
        _prepareHelp: function () {
            var self = this,
                editor = self.editor,
                prefixCls = editor.get('prefixCls'),
                cfg = self.config,
                draftCfg = cfg.draft,
                help = new Node(draftCfg['helpHTML'] || &quot;&quot;);
            var arrowCss = &quot;height:0;&quot; +
                &quot;position:absolute;&quot; +
                &quot;font-size:0;&quot; +
                &quot;width:0;&quot; +
                &quot;border:8px #000 solid;&quot; +
                &quot;border-color:#000 transparent transparent transparent;&quot; +
                &quot;border-style:solid dashed dashed dashed;&quot;;
            var arrow = new Node(&quot;&lt;div style='&quot; +
                arrowCss +
                &quot;border-top-color:#CED5E0;&quot; +
                &quot;'&gt;&quot; +
                &quot;&lt;div style='&quot; +
                arrowCss +
                &quot;left:-8px;&quot; +
                &quot;top:-10px;&quot; +
                &quot;border-top-color:white;&quot; +
                &quot;'&gt;&quot; +
                &quot;&lt;/div&gt;&quot; +
                &quot;&lt;/div&gt;&quot;);
            help.append(arrow);
            help.css({
                border: &quot;1px solid #ACB4BE&quot;,
                &quot;text-align&quot;: &quot;left&quot;
            });
            self.helpPopup = new Overlay({
                content: help,
                prefixCls: prefixCls + 'editor-',
                width: help.width() + &quot;px&quot;,
                zIndex: Editor.baseZIndex(Editor.ZIndexManager.OVERLAY),
                mask: false
            }).render();
            self.helpPopup.get(&quot;el&quot;)
                .css(&quot;border&quot;, &quot;none&quot;);
            self.helpPopup.arrow = arrow;
        },
        _realHelp: function () {
            var win = this.helpPopup,
                helpBtn = this.helpBtn,
                arrow = win.arrow;
            win.show();
            var off = helpBtn.offset();
            win.get(&quot;el&quot;).offset({
                left: (off.left - win.get(&quot;el&quot;).width()) + 17,
                top: (off.top - win.get(&quot;el&quot;).height()) - 7
            });
            arrow.offset({
                left: off.left - 2,
                top: off.top - 8
            });
        },
        disable: function () {
            this.holder.css(&quot;visibility&quot;, &quot;hidden&quot;);
        },
        enable: function () {
            this.holder.css(&quot;visibility&quot;, &quot;&quot;);
        },
        sync: function () {
            var self = this,
                i,
                draftLimit = self.draftLimit,
                timeTip = self.timeTip,
                versions = self.versions,
                drafts = self._getDrafts(),
                draft, tip;

            if (drafts.length &gt; draftLimit) {
                drafts.splice(0, drafts.length - draftLimit);
            }

            versions.removeItems(true);

            for (i = 0; i &lt; drafts.length; i++) {
                draft = drafts[i];
                tip = (draft.auto ? &quot;自动&quot; : &quot;手动&quot;) + &quot;保存于 : &quot;
                    + date(draft.date);
                versions.addItem({
                    content: tip,
                    value: i
                });
            }

            if (!drafts.length) {
                versions.addItem({
                    disabled: true,
                    content: '尚无历史',
                    value: ''
                });
            }

            timeTip.html(tip);
            localStorage.setItem(self._getSaveKey(),
                (localStorage == window.localStorage) ?
                    encodeURIComponent(Json.stringify(drafts))
                    : drafts);
        },

        save: function (auto) {
            var self = this,
                drafts = self._getDrafts(),
                editor = self.editor,
            //不使用rawdata
            //undo 只需获得可视区域内代码
            //可视区域内代码！= 最终代码
            //代码模式也要支持草稿功能
            //统一获得最终代码
                data = editor.getFormatData();

            //如果当前内容为空，不保存版本
            if (!data) {
                return;
            }

            if (drafts[drafts.length - 1] &amp;&amp;
                data == drafts[drafts.length - 1].content) {
                drafts.length -= 1;
            }
            self.drafts = drafts.concat({
                content: data,
                date: new Date().getTime(),
                auto: auto
            });
            self.sync();
        },

        recover: function (ev) {
            var self = this,
                editor = self.editor,
                drafts = self._getDrafts(),
                v = ev.target.get(&quot;value&quot;);
            if (confirm(&quot;确认恢复 &quot; + date(drafts[v].date) + &quot; 的编辑历史？&quot;)) {
                editor.execCommand(&quot;save&quot;);
                editor.setData(drafts[v].content);
                editor.execCommand(&quot;save&quot;);
            }
            ev.halt();
        },

        destroy: function () {
            destroyRes.call(this);
        }
    });

    function init(editor, config) {
        var d = new Draft(editor, config);
        editor.on(&quot;destroy&quot;, function () {
            d.destroy();
        });
    }

    function DraftPlugin(config) {
        this.config = config || {};
    }

    S.augment(DraftPlugin, {
        pluginRenderUI: function (editor) {
            var config = this.config;
            if (localStorage.ready) {
                localStorage.ready(function () {
                    init(editor, config);
                });
            } else {
                init(editor, config);
            }
        }
    });

    return DraftPlugin;
}, {
    &quot;requires&quot;: ['json', &quot;editor&quot;, &quot;./local-storage&quot;, &quot;overlay&quot;, './menubutton']
});</pre>
</body>
</html>
